#include <stdio.h>
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_eth.h"
#include "esp_http_server.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs.h"
#include "cJSON.h"
#include "esp_log.h"

const char *TAG = "YEE-LIGHT";
static char *AP_LIST;
static const uint8_t POWER_SWITCH_PIN = 27;
static EventGroupHandle_t wifi_event_group;
const EventBits_t SCAN_DONE_BIT = BIT0;
static BaseType_t task_handler = -1;

static void scan_task(void *pvParameter)
{
    while (1)
    {
        xEventGroupWaitBits(wifi_event_group, SCAN_DONE_BIT, 0, 1, portMAX_DELAY); // 等待事件位被重置
        ESP_LOGI(TAG, "");
        xEventGroupClearBits(wifi_event_group, SCAN_DONE_BIT); //清除事件标志位

        uint16_t ap_count = 0;
        esp_wifi_scan_get_ap_num(&ap_count); // 获取扫描到的AP数量

        if (ap_count == 0) // 没有扫描到任何AP
        {
            ESP_LOGI(TAG, "没有扫描到任何AP");
            AP_LIST = malloc(3);
            memcpy(AP_LIST, "[]\0", 3);
            return;
        }
        else
        {
            ESP_LOGI(TAG, "扫描完成，扫描到%d个AP信号", ap_count);
        }
        // 为 wifi_ap_record_t 结构体数组分配空间
        wifi_ap_record_t *list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * ap_count);
        // 获取上一次扫描中找到的AP列表，填充到list
        ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, list));
        // 拼接JSON字符串
        uint8_t *ap_info = malloc(120 * ap_count + 2);
        memcpy(ap_info, "[", 1);
        uint32_t total_len = 1;
        for (int i = 0; i < ap_count; i++)
        {
            char *item = malloc(120);
            int32_t len = sprintf(item, "{\"authmode\":%d,\"ssid\":\"%s\",\"rssi\":%d},", list[i].authmode, list[i].ssid, list[i].rssi);
            memcpy(&ap_info[total_len], item, len);
            total_len += len;
            free(item);
        }
        memcpy(&ap_info[total_len - 1], "]", 1);
        memcpy(&ap_info[total_len], "\0", 1);
        AP_LIST = malloc(total_len + 1);
        memcpy(AP_LIST, ap_info, total_len + 1);
        free(ap_info);
        free(list);
    }
    // scan again
    //  vTaskDelay(5000 / portTICK_PERIOD_MS);//调用延时函数，再次扫描
    //The true parameter cause the function to block until the scan is done.
    // ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, 1));//扫描所有可用的AP。
}

static esp_err_t scan_wifi_list_handler(httpd_req_t *req)
{
    wifi_scan_config_t scan_config = {
        .ssid = NULL,
        .bssid = NULL,
        .channel = 0,
        .scan_type = 0,
        .show_hidden = 1};
    if (task_handler != -1)
        ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, true));
    else
    {
        ESP_LOGI(TAG, "创建扫描任务");
        task_handler = xTaskCreate(&scan_task, "scan_task", 2048, NULL, 15, NULL); //创建扫描任务
        ESP_LOGI(TAG, "任务创建完成，开始扫描");
        ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, true));
    }

    printf("%s", AP_LIST);
    httpd_resp_set_hdr(req, "Host", TAG);
    httpd_resp_set_type(req, "application/json");
    httpd_resp_send(req, AP_LIST, -1);

    free(AP_LIST);

    return ESP_OK;
}

const httpd_uri_t scan_wifi_list = {
    .uri = "/wifi",
    .method = HTTP_GET,
    .handler = scan_wifi_list_handler,
    .user_ctx = NULL};

static esp_err_t set_wifi_config_handler(httpd_req_t *req)
{
    int ret, curr = 0, remaining = req->content_len;
    char buf[100], *content = malloc(remaining + 1);

    while (remaining > 0)
    {
        ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
        if (ret <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT)
            {
                continue;
            }
            return ESP_FAIL;
        }

        remaining -= ret;
        memcpy(content + curr, &buf, ret);
        curr += ret;
    }
    memset(&content + curr, 0, 1);

    char *res;
    cJSON *json = cJSON_Parse(content);
    cJSON *ssid = cJSON_GetObjectItem(json, "ssid");
    cJSON *pass = cJSON_GetObjectItem(json, "pass");
    if (NULL == ssid)
    {
        res = "{\"status\":\"ERR\",\"message\":\"软路由AP名不能为空\"}";
        httpd_resp_set_hdr(req, "Host", TAG);
        httpd_resp_set_type(req, "application/json");
        httpd_resp_send(req, res, -1);
        return ESP_OK;
    }

    nvs_handle_t wifi_config_handle;
    esp_err_t err = nvs_open("YEE_WIFI_CONF", NVS_READWRITE, &wifi_config_handle);
    ESP_ERROR_CHECK(err);

    uint32_t ssid_len = strlen(ssid->valuestring) + 1;
    uint32_t pass_len = strlen(pass->valuestring) + 1;
    char *wifi_ssid = malloc(ssid_len);
    char *wifi_pass = malloc(pass_len);

    memset(wifi_ssid, 0, ssid_len);
    memset(wifi_pass, 0, pass_len);

    memcpy(wifi_ssid, ssid->valuestring, ssid_len - 1);
    memcpy(wifi_pass, pass->valuestring, pass_len - 1);

    nvs_set_u32(wifi_config_handle, "SSID_LEN", ssid_len);
    nvs_set_u32(wifi_config_handle, "PASS_LEN", pass_len);

    nvs_set_str(wifi_config_handle, "WIFI_SSID", wifi_ssid);
    nvs_set_str(wifi_config_handle, "WIFI_PASS", wifi_pass);

    nvs_commit(wifi_config_handle);
    nvs_close(wifi_config_handle);

    cJSON_Delete(json);
    free(content);
    ESP_LOGI(TAG, "保存WIFI信息到NVS，三秒钟后系统将重启，并进入到正常运行模式");
    res = "{\"status\":\"OK\",\"message\":\"保存WIFI信息到NVS，三秒钟后系统将重启，并进入到正常运行模式\"}";
    // end response
    httpd_resp_set_hdr(req, "Host", TAG);
    httpd_resp_set_type(req, "application/json");
    httpd_resp_send(req, res, -1);
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    esp_restart();
    return ESP_OK;
}

const httpd_uri_t set_wifi_config = {
    .uri = "/wifi",
    .method = HTTP_POST,
    .handler = set_wifi_config_handler,
    .user_ctx = NULL};

static esp_err_t restart_handler(httpd_req_t *req)
{
    httpd_resp_set_hdr(req, "host", "yee-light");
    httpd_resp_set_type(req, "application/json");
    ESP_LOGI(TAG, "三秒后，系统将重新启动");
    httpd_resp_send(req, "{\"status\":\"OK\",\"message\":\"三秒后，系统将重新启动\"}", -1);
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    esp_restart();
    return ESP_OK;
}

const httpd_uri_t restart = {
    .uri = "/restart",
    .method = HTTP_POST,
    .handler = restart_handler,
    .user_ctx = NULL};

void clear_wifi_nvs_data()
{
    nvs_handle_t wifi_config_handle;
    esp_err_t err = nvs_open("YEE_WIFI_CONF", NVS_READWRITE, &wifi_config_handle);
    ESP_ERROR_CHECK(err);
    ESP_ERROR_CHECK(nvs_erase_all(wifi_config_handle));
}
static esp_err_t reset_handler(httpd_req_t *req)
{
    clear_wifi_nvs_data();
    httpd_resp_set_hdr(req, "Host", TAG);
    httpd_resp_set_type(req, "application/json");
    ESP_LOGI(TAG, "NVS数据清理完成，三秒后系统将重启，并进入配网模式");
    httpd_resp_send(req, "{\"status\":\"OK\",\"message\":\"NVS数据清理完成，三秒后系统将重启，并进入配网模式\"}", -1);
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    esp_restart();
    return ESP_OK;
}

const httpd_uri_t reset = {
    .uri = "/reset",
    .method = HTTP_POST,
    .handler = reset_handler,
    .user_ctx = NULL};

static esp_err_t power_handler(httpd_req_t *req)
{
    int ret = 0, curr = 0, remaining = req->content_len;
    char buf[100], *content = malloc(remaining + 1);
    while (remaining > 0)
    {
        ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
        if (ret <= 0)
        {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT)
            {
                continue;
            }
            return ESP_FAIL;
        }

        remaining -= ret;
        memcpy(content + curr, &buf, ret);
        curr += ret;
    }
    memcpy(content + curr, "\0", 1);
    gpio_pad_select_gpio(POWER_SWITCH_PIN);
    gpio_set_direction(POWER_SWITCH_PIN, GPIO_MODE_OUTPUT);

    httpd_resp_set_hdr(req, "Host", TAG);
    httpd_resp_set_type(req, "application/json");

    if (strlen(content) == 2 && content[0] == 'o' && content[1] == 'n')
    {
        httpd_resp_send(req, "{\"status\":\"OK\",\"message\":\"开灯\"}", -1);
        ESP_LOGI(TAG, "开灯");
        gpio_set_level(POWER_SWITCH_PIN, 1);
    }
    else if (strlen(content) == 3 && content[0] == 'o' && content[1] == 'f' && content[2] == 'f')
    {
        httpd_resp_send(req, "{\"status\":\"OK\",\"message\":\"关灯\"}", -1);
        ESP_LOGI(TAG, "关灯");
        gpio_set_level(POWER_SWITCH_PIN, 0);
    }
    else
    {
        httpd_resp_send(req, "{\"status\":\"ERR\",\"message\":\"未知错误\"}", -1);
    }
    return ESP_OK;
}

const httpd_uri_t power = {
    .uri = "/power",
    .method = HTTP_POST,
    .handler = power_handler,
    .user_ctx = NULL};

static esp_err_t change_mode_handler(httpd_req_t *req)
{
    return ESP_OK;
}

const httpd_uri_t change_mode = {
    .uri = "/mode",
    .method = HTTP_POST,
    .handler = change_mode_handler,
    .user_ctx = NULL};

static esp_err_t change_color_handler(httpd_req_t *req)
{
    return ESP_OK;
}

const httpd_uri_t change_colour = {
    .uri = "/colour",
    .method = HTTP_POST,
    .handler = change_color_handler,
    .user_ctx = NULL};

static esp_err_t change_colour_temperature_handler(httpd_req_t *req)
{
    return ESP_OK;
}

const httpd_uri_t change_colour_temperature = {
    .uri = "/temperature",
    .method = HTTP_POST,
    .handler = change_colour_temperature_handler,
    .user_ctx = NULL};

static esp_err_t change_brightness_handler(httpd_req_t *req)
{
    return ESP_OK;
}

const httpd_uri_t change_brightness = {
    .uri = "/brightness",
    .method = HTTP_POST,
    .handler = change_brightness_handler,
    .user_ctx = NULL};